from appserver import db_store
from sqlalchemy import or_
from sqlalchemy import func
import copy


class TreeModelBase(db_store.Model):
    __abstract__ = True    # 使TreeModelBase不必与数据表关联

    id = db_store.Column(db_store.Integer, primary_key=True, comment=u'ID')
    parent_id = db_store.Column(db_store.Integer, nullable=False, comment=u"父ID")
    path = db_store.Column(db_store.String(255), nullable=False, comment=u"路径")
    depth = db_store.Column(db_store.Integer, comment=u"深度")
    child_num = db_store.Column(db_store.Integer, comment=u"子类数量")
    dis_order = db_store.Column(db_store.Integer, comment=u"排序")

    def __init__(self):
        self.id = 0
        self.parent_id = 0
        self.dis_order = 0
        self.depth = 0
        self.child_num = 0

    # def from_dict(self, rev_source):
    #     source = copy.deepcopy(rev_source)
    #     print('source', source)
    #     if "ParentId" in source:
    #         source["parent_id"] = source.pop("ParentId")
    #     if "Level" in source:
    #         source["depth"] = source.pop("Level")
    #     if "children" in source:
    #         source.pop("children")
    #     for k in source:
    #         print('k',k)
    #         try:
    #             getattr(self, k)
    #             # print('getattr',getattr(self, k))
    #         except AttributeError as e:
    #             print(e)
    #             raise RuntimeError("数据格式错误")
    #         setattr(self, k, source[k])
    #         # print('setattr',setattr(self, k, source[k]))

    def from_dict(self, rev_source):
        source = copy.deepcopy(rev_source)
        print('source', source)
        if "parent_id" in source:
            source["parent_id"] = source.pop("parent_id")
        if "level" in source:
            source["depth"] = source.pop("level")
        if "children" in source:
            source.pop("children")
        for k in source:
            print('k',k)
            try:
                getattr(self, k)
                # print('getattr',getattr(self, k))
            except AttributeError as e:
                print(e)
                raise RuntimeError("数据格式错误")
            setattr(self, k, source[k])
            # print('setattr',setattr(self, k, source[k]))

    def to_dict(self):
        rdic = {}
        for c in self.__table__.columns:
            if c.name == "parent_id":
                # rdic["ParentId"] = getattr(self, c.name, None)
                rdic["parent_id"] = getattr(self, c.name, None)
            elif c.name == "depth":
                # rdic["Level"] = getattr(self, c.name, None)
                rdic["level"] = getattr(self, c.name, None)
            else:
                rdic[c.name] = getattr(self, c.name, None)
        return rdic

    def get_max_id(self):
        val = db_store.session.query(func.max(self.__class__.id)).scalar()
        if not val:
            return 0
        else:
            return val

    def save(self):
        try:
            if self.id == 0:  # 新增数据
                self.id = self.get_max_id() + 1
                if self.parent_id == 0:  # 添加为一级节点
                    self.path = str(self.id)
                    self.depth = 1
                    self.child_num = 0
                else:
                    parent_entity = self.get_entity_by_id(self.parent_id)  # 获取父节点
                    self.path = parent_entity.path + ',' + str(self.id)
                    self.depth = len(self.path.split(','))
                    self.child_num = 0
                    parent_entity.child_num = parent_entity.child_num + 1
                    parent_entity.save()
            else:  # 更新数据
                old_entity = self.get_entity_by_id(self.id)  # 获取旧数据用于判断是否更换了父节点
                old_parent_entity = self.get_entity_by_id(old_entity.parent_id)
                parent_entity = self.get_entity_by_id(self.parent_id)  # 获取父节点数据
                if self.parent_id != old_entity.parent_id:  # 判断是否更换了父ID
                    if str(self.id) in parent_entity.path.split(','):  # 判断是否移动到自己的子节点下
                        raise RuntimeError("不能移动到自己的子节点下")
                    self.path = parent_entity.path + ',' + str(self.id)  # 更新自己的path
                    self.depth = len(self.path.split(','))  # 更新自己的深度
                    if not (old_parent_entity is None):  # 判断旧的父节点是否为空，也就是原来是不是最顶层的模块
                        old_parent_entity.child_num = old_parent_entity.child_num - 1
                        old_parent_entity.save()
                    parent_entity.child_num = parent_entity.child_num + 1  # 父节点的子节点数减去1
                    parent_entity.save()
                    pass  # 获取所有深度的子节点
                    nodes = self.query.filter(or_(self.path.like(old_entity.path + ',%'), self.path.like('%,'+old_entity.path+',%')))
                    for item in nodes:
                        item.path = item.path.replace(old_entity.path, self.path)
                        item.depth = len(item.path.split(','))
                        item.save()
            db_store.session.add(self)
            db_store.session.commit()
            return True
        except Exception as err:
            print('保存错误了,死俏皮哦')
            print(err)
            db_store.session.rollback()
            return False

    def delete(self):
        try:
            if self.child_num > 0:
                raise RuntimeError("存在子节点，请先删除子节点.")
            parent_entity = self.get_entity_by_id(self.parent_id)  # 更新(查询)父节点
            if not (parent_entity is None):  # 判断旧的父节点是否为空，也就是原来是不是最顶层的模块(如果不为空)
                #  删除了一个子节点,所以他的父节点的child_num应该减1
                parent_entity.child_num = parent_entity.child_num - 1
                parent_entity.save()
            db_store.session.delete(self)
            db_store.session.commit()
            return True
        except Exception as err:
            print(err)
            db_store.session.rollback()
            return False

    def get_list_all(self):
        return self.query.all()

    def get_list_by_pid(self, pid):
        return self.query.filter_by(parent_id=pid).all()

    def get_entity_by_id(self, id):
        # print(555555555,copy.deepcopy(self.query.filter_by(id=id).first()))
        return copy.deepcopy(self.query.filter_by(id=id).first())

    def get_left_tree(self, pid):
        """
        根据父ID返回模块树
        :param pid: 父ID
        :return: list
        """

        result = []
        try:
            nodes = self.query.filter_by(parent_id = pid).order_by(db_store.desc("dis_order")).all()
            # print('nodes:',nodes)
            for item in nodes:
                # print('item:',item)
                # tmp = {}
                tmp = item.to_dict()
                if item.child_num > 0:
                    tmp['children'] = self.get_left_tree(item.id)   # 这个用到递归,所以会遍历所以的子节点
                result.append(tmp)
            return result
        except Exception as err:
            print(err)
            return []

    def get_tree_by_pid(self, pid):
        """
        根据父ID返回模块树
        :param pid: 父ID
        :return: list
        """

        result = []
        try:
            nodes = self.query.filter_by(parent_id=pid).order_by(db_store.desc("dis_order")).all()
            # print('nodes:', nodes)
            for item in nodes:
                # print('item:', item)
                tmp = item.to_dict()
                result.append(tmp)
                if self.query.filter_by(parent_id=item.id).first():
                #if item.child_num > 0:
                    tmp['children'] = self.get_tree_by_pid(item.id)
            return result
        except Exception as err:
            print(err)
            return []